package cn.chench.util;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 日志工具
 * 
 * @author chencaihui
 * @datetime 创建时间：2019年8月29日 下午2:44:18
 */
public class LoggerUtil {

	private static final ThreadLocal<Long> threadLocal = new ThreadLocal<Long>();
	private static Map<String, Logger> loggerMap = new HashMap<String, Logger>();
	private static final Logger logger = LoggerFactory.getLogger(LoggerUtil.class);

	private static final Logger getLogger(final String classesName) {
		if (!loggerMap.containsKey(classesName)) {
			try {
				Class<?> classes = Class.forName(classesName);
				final Logger logger = LoggerFactory.getLogger(classes);
				loggerMap.put(classesName, logger);
				return logger;
			} catch (ClassNotFoundException e) {
				logger.error("初始化logger异常", e);
				return logger;
			}
		}
		return loggerMap.get(classesName);
	}

	/**
	 * 记录开始时间戳
	 * 
	 * @author chencaihui
	 * @date 2019年12月13日 上午11:22:48
	 */
	public static void start() {
		long time = System.currentTimeMillis();
		threadLocal.set(time);
		final StackTraceElement stackTraceElement = Thread.currentThread().getStackTrace()[2];
		getLogger(stackTraceElement.getClassName()).info(
				stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName() + "--->开始start..." + time);
	}

	/**
	 * 计算耗时
	 * 
	 * @author chencaihui
	 * @date 2019年12月13日 上午11:23:04
	 * @param msg
	 */
	public static void end(String... msg) {
		StringBuilder msgsb = new StringBuilder();
		for (String message : msg) {
			msgsb.append("--->" + message);
		}
		Long startTime = threadLocal.get();
		if (startTime != null && startTime.longValue() > 0) {
			msgsb.append("--->耗时(毫秒)：" + (System.currentTimeMillis() - startTime.longValue()));
			threadLocal.remove();// 置空
		}
		final StackTraceElement stackTraceElement = Thread.currentThread().getStackTrace()[2];
		getLogger(stackTraceElement.getClassName())
				.info(stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName() + msgsb.toString());
	}

	/**
	 * 计算耗时
	 * 
	 * @author chencaihui
	 * @date 2019年12月13日 上午11:23:04
	 */
	public static void endError(String... msg) {
		StringBuilder msgsb = new StringBuilder();
		for (String message : msg) {
			msgsb.append("--->" + message);
		}
		long consumeTime = 0;
		long endTime = System.currentTimeMillis();
		Long startTime = threadLocal.get();
		if (startTime != null && startTime.longValue() > 0) {
			consumeTime = endTime - startTime.longValue();
			msgsb.append("--->耗时(毫秒)：" + consumeTime);
			threadLocal.remove();// 置空
		}
		final StackTraceElement stackTraceElement = Thread.currentThread().getStackTrace()[2];
		String className = stackTraceElement.getClassName();
		String methodName = stackTraceElement.getMethodName();
		getLogger(className).error(className + "." + methodName + msgsb.toString());
	}

	/**
	 * 计算耗时
	 * 
	 * @author chencaihui
	 * @date 2019年12月13日 上午11:23:04
	 */
	public static void endError(Exception e) {
		final StackTraceElement stackTraceElement = Thread.currentThread().getStackTrace()[2];
		String className = stackTraceElement.getClassName();
		String methodName = stackTraceElement.getMethodName();
		StringBuilder msgsb = new StringBuilder(className + "." + methodName);
		long consumeTime = 0;
		long endTime = System.currentTimeMillis();
		Long startTime = threadLocal.get();
		if (startTime != null && startTime.longValue() > 0) {
			consumeTime = endTime - startTime.longValue();
			msgsb.append("--->耗时(毫秒)：" + consumeTime);
			threadLocal.remove();// 置空
		}
		String errormsg = getErrorMessage(e);
		getLogger(className).error(msgsb.toString() + "：" + errormsg);
	}
	
	/**
	 * 计算耗时
	 * @author chencaihui 
	 * @date 2020年6月8日 下午3:17:36 
	 * @param e
	 */
	public static void end(Exception e) {
		final StackTraceElement stackTraceElement = Thread.currentThread().getStackTrace()[2];
		String className = stackTraceElement.getClassName();
		String methodName = stackTraceElement.getMethodName();
		StringBuilder msgsb = new StringBuilder(className + "." + methodName);
		long consumeTime = 0;
		long endTime = System.currentTimeMillis();
		Long startTime = threadLocal.get();
		if (startTime != null && startTime.longValue() > 0) {
			consumeTime = endTime - startTime.longValue();
			msgsb.append("--->耗时(毫秒)：" + consumeTime);
			threadLocal.remove();// 置空
		}
		String errormsg = getErrorMessage(e);
		getLogger(className).error(msgsb.toString() + "：" + errormsg);
	}

	/**
	 * 计算耗时
	 * @author chencaihui
	 * @date 2019年12月13日 上午11:23:04
	 */
	public static void end(String msg, Exception e) {
		final StackTraceElement stackTraceElement = Thread.currentThread().getStackTrace()[2];
		String className = stackTraceElement.getClassName();
		String methodName = stackTraceElement.getMethodName();
		StringBuilder msgsb = new StringBuilder(className + "." + methodName + "--->" + msg);
		long consumeTime = 0;
		long endTime = System.currentTimeMillis();
		Long startTime = threadLocal.get();
		if (startTime != null && startTime.longValue() > 0) {
			consumeTime = endTime - startTime.longValue();
			msgsb.append("--->耗时(毫秒)：" + consumeTime);
			threadLocal.remove();// 置空
		}
		String errormsg = getErrorMessage(e);
		getLogger(className).error(msgsb.toString() + "：" + errormsg);
	}

	public static void info(String... msg) {
		StringBuilder msgsb = new StringBuilder();
		for (String message : msg) {
			msgsb.append("--->" + message);
		}
		final StackTraceElement stackTraceElement = Thread.currentThread().getStackTrace()[2];
		getLogger(stackTraceElement.getClassName())
				.info(stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName() + msgsb.toString());
	}

	public static void warn(String... msg) {
		StringBuilder msgsb = new StringBuilder();
		for (String message : msg) {
			msgsb.append("--->" + message);
		}
		final StackTraceElement stackTraceElement = Thread.currentThread().getStackTrace()[2];
		getLogger(stackTraceElement.getClassName())
				.warn(stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName() + msgsb.toString());
	}

	public static void error(String... msg) {
		final StackTraceElement stackTraceElement = Thread.currentThread().getStackTrace()[2];
		String className = stackTraceElement.getClassName();
		String methodName = stackTraceElement.getMethodName();
		StringBuilder msgsb = new StringBuilder();
		for (String message : msg) {
			msgsb.append("--->" + message);
		}
		getLogger(className).error(className + "." + methodName + "--->" + msgsb.toString());
	}

	public static void error(Exception e) {
		final StackTraceElement stackTraceElement = Thread.currentThread().getStackTrace()[2];
		String className = stackTraceElement.getClassName();
		String methodName = stackTraceElement.getMethodName();
		String errormsg = getErrorMessage(e);
		getLogger(className).error(className + "." + methodName + "--->" + errormsg);
	}

	public static void error(String msg, Exception e) {
		final StackTraceElement stackTraceElement = Thread.currentThread().getStackTrace()[2];
		String className = stackTraceElement.getClassName();
		String methodName = stackTraceElement.getMethodName();
		String errormsg = getErrorMessage(e);
		getLogger(className).error(className + "." + methodName + "--->" + msg + "：" + errormsg);
	}
	
	public static void error(String msg, Throwable e) {
		final StackTraceElement stackTraceElement = Thread.currentThread().getStackTrace()[2];
		String className = stackTraceElement.getClassName();
		String methodName = stackTraceElement.getMethodName();
		String errormsg = getErrorMessage(e);
		getLogger(className).error(className + "." + methodName + "--->" + msg + "：" + errormsg);
	}

	public static final String getErrorMessage(final Exception ex) {
		ByteArrayOutputStream baos = null;
		PrintStream ps = null;
		try{
			baos = new ByteArrayOutputStream();
			ps = new PrintStream(baos);
			ex.printStackTrace(ps);
			return baos.toString();
		} catch (Exception e) {
			return ex.getMessage();
		} finally {
			try {
				if(baos!=null) baos.close();
				if(ps!=null) ps.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	public static final String getErrorMessage(final Throwable ex) {
		ByteArrayOutputStream baos = null;
		PrintStream ps = null;
		try{
			baos = new ByteArrayOutputStream();
			ps = new PrintStream(baos);
			ex.printStackTrace(ps);
			return baos.toString();
		} catch (Exception e) {
			return ex.getMessage();
		} finally {
			try {
				if(baos!=null) {
					baos.flush();
					baos.close();
				}
				if(ps!=null){
					ps.flush();
					ps.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
}
